package com.yfs.cloud.filter;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;

import com.yfs.cloud.commons.BusinessException;
import com.yfs.cloud.commons.Constants;
import com.yfs.cloud.commons.ResultCode;
import com.yfs.cloud.config.BusinessProperties;
import com.yfs.cloud.util.JWTUtil;

import io.jsonwebtoken.Claims;
import reactor.core.publisher.Mono;

/**
* @Company: 影法師工作室
* @Description: jwt 过滤器,仅仅实现认证功能, 至于授权、鉴权在各个微服务的AuthInterceptor去做, 网关仅仅做认证(也就是解析 jwt 而已)
* @author 影法師  
* @date 2020年8月25日 下午9:16:27 
* @version V1.0
 */
@SuppressWarnings("all")
@Component
public class JWTFilter implements GlobalFilter, Ordered {

	@Autowired
	private JWTUtil jwtUtil;

	@Autowired
	private BusinessProperties businessProperties;

	/**
	 * 网关全局过滤器
	 */
	@Override
	public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
		// 如果不开启 jwt 认证, 则直接放行
		if (!businessProperties.getJwt().isEnabled()) {
			return chain.filter(exchange);
		}
		// 获取Request、Response对象
		ServerHttpRequest request = exchange.getRequest();
		// 获取访问的 uri, 这类似于 /api/lr/register、/api/user/findUserAuthority/1
		String path = request.getURI().getPath();
		// 如果是白名单中的接口的话, 则不需要认证 jwt, 直接放行
		for (String whiteCheck : businessProperties.getJwt().getWhitelist()) {
			if (path.contains(whiteCheck)) {
				return chain.filter(exchange);
			}
		}
		// 获取头文件中的令牌信息
		String jwt = request.getHeaders().getFirst(Constants.JWT_HEADER);
		// 如果没带令牌过来
		if (StringUtils.isBlank(jwt)) {
			throw new BusinessException(ResultCode.JWT_EMPTY);
		}
		// 解析令牌数据
		Claims claims = jwtUtil.checkJWT(jwt);
		// 解析得到用户 id
		Long userId = claims.get(Constants.USER_ID, Long.class);
		// 我们不想让各个微服务又去解析一次jwt(因为解析jwt这件事情就给网关来做就好了), 所以直接将 userId 放进请求头,
		// 这样各个微服务直接就知道该用户是谁了, mutate
		// 的意思是变异、转换的意思
		request.mutate().header(Constants.USER_ID, userId.toString());
		// 令牌有效, 予以放行, 此时 http 头中依旧带着 jwt 转发到了各个微服务去了,
		// 但是因为我们已经将userId放进了请求头,所以各个微服务是不需要再一次解析jwt的
		return chain.filter(exchange);
	}

	/***
	 * 过滤器执行顺序, 越小越先执行
	 */
	@Override
	public int getOrder() {
		return 0;
	}

}
